package com.loong.framework.utils;

import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.URI;
import java.net.URISyntaxException;
import java.net.URL;
import java.net.URLConnection;
import java.nio.charset.StandardCharsets;
import java.util.HashMap;
import java.util.Map;

public class WxUtil {
  private static final Logger log = LoggerFactory.getLogger(WxUtil.class);

  public static Object getPhoneNumber(String encryptedData, String code, String iv) {
    // 传入code后然后获取openid和session_key的，把他们封装到json里面
    JsonNode json = getSessionKeyOpenid(code);
    String session_key = "";
    if (json != null) {
      session_key = json.get("session_key").asText();
      // 被加密的数据
      byte[] dataByte = java.util.Base64.getDecoder().decode(encryptedData);
      // 加密秘钥
      byte[] keyByte = java.util.Base64.getDecoder().decode(session_key);
      // 偏移量
      byte[] ivByte = java.util.Base64.getDecoder().decode(iv);
      try {
        // 如果密钥不足16位，那么就补足.  这个if 中的内容很重要
        int base = 16;
        if (keyByte.length % base != 0) {
          int groups = keyByte.length / base + 1;
          byte[] temp = new byte[groups * base];
          java.util.Arrays.fill(temp, (byte) 0);
          System.arraycopy(keyByte, 0, temp, 0, keyByte.length);
          keyByte = temp;
        }
        // 初始化
        javax.crypto.Cipher cipher = javax.crypto.Cipher.getInstance("AES/CBC/PKCS5Padding");
        javax.crypto.spec.SecretKeySpec spec = new javax.crypto.spec.SecretKeySpec(keyByte, "AES");
        java.security.AlgorithmParameters parameters =
            java.security.AlgorithmParameters.getInstance("AES");
        parameters.init(new javax.crypto.spec.IvParameterSpec(ivByte));
        cipher.init(javax.crypto.Cipher.DECRYPT_MODE, spec, parameters); // 初始化
        byte[] resultByte = cipher.doFinal(dataByte);
        if (null != resultByte && resultByte.length > 0) {
          String result = new String(resultByte, java.nio.charset.StandardCharsets.UTF_8);
          ObjectMapper objectMapper = new ObjectMapper();
          return objectMapper.readTree(result);
        }
      } catch (Exception e) {
        log.error("解密失败", e);
      }
    }
    return null;
  }

  /**
   * 获取微信小程序 session_key 和 openid
   *
   * @param code 调用微信登陆返回的Code
   * @return
   */
  public static JsonNode getSessionKeyOpenid(String code) {
    // 微信端登录code值
    String requestUrl = "https://api.weixin.qq.com/sns/jscode2session"; // 请求地址
    Map<String, String> requestUrlParam = new HashMap<>();
    requestUrlParam.put("appid", "wx2f7b849acf031253"); // 开发者设置中的appId
    requestUrlParam.put("secret", "e8f5e6386b2a221a6760501263b93f7d"); // 开发者设置中的appSecret
    requestUrlParam.put("js_code", code); // 小程序调用wx.login返回的code
    requestUrlParam.put("grant_type", "authorization_code"); // 默认参数 authorization_code

    // 发送post请求读取调用微信 https://api.weixin.qq.com/sns/jscode2session 接口获取openid用户唯一标识
    return sendPost(requestUrl, requestUrlParam);
  }

  /**
   * 向指定 URL 发送POST方法的请求
   *
   * @param url 发送请求的 URL
   * @param paramMap 请求参数
   * @return JsonNode
   */
  public static JsonNode sendPost(String url, Map<String, String> paramMap) {
    PrintWriter out = null;
    BufferedReader in = null;
    StringBuilder result = new StringBuilder();

    StringBuilder param = new StringBuilder();

    for (String key : paramMap.keySet()) {
      param.append(key).append("=").append(paramMap.get(key)).append("&");
    }

    try {
      URLConnection conn = getUrlConnection(url);
      // 获取URLConnection对象对应的输出流
      out = new PrintWriter(conn.getOutputStream());
      // 发送请求参数
      out.print(param);
      // flush输出流的缓冲
      out.flush();
      // 定义BufferedReader输入流来读取URL的响应
      in = new BufferedReader(new InputStreamReader(conn.getInputStream(), StandardCharsets.UTF_8));
      String line;
      while ((line = in.readLine()) != null) {
        result.append(line);
      }
      ObjectMapper objectMapper = new ObjectMapper();
      return objectMapper.readTree(result.toString());
    } catch (Exception e) {
      log.error(e.getMessage(), e);
      return null;
    } finally {
      try {
        if (out != null) {
          out.close();
        }
        if (in != null) {
          in.close();
        }
      } catch (IOException ex) {
        log.error(ex.getMessage(), ex);
      }
    }
  }

  private static URLConnection getUrlConnection(String url) throws URISyntaxException, IOException {
    URI uri = new URI(url);
    URL realUrl = uri.toURL();
    // 打开和URL之间的连接
    URLConnection conn = realUrl.openConnection();
    // 设置通用的请求属性
    conn.setRequestProperty("accept", "*/*");
    conn.setRequestProperty("connection", "Keep-Alive");
    conn.setRequestProperty("Accept-Charset", "utf-8");
    conn.setRequestProperty("user-agent", "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1;SV1)");
    // 发送POST请求必须设置如下两行
    conn.setDoOutput(true);
    conn.setDoInput(true);
    return conn;
  }
}
